import { PokerCard } from "./card";

// 定义扑克集合
export class PokerSet {

  private _cards: Array<PokerCard>;

  constructor() {
    this._cards = new Array<PokerCard>();
  }

  // 创建新的扑克集
  public NewPokerSet() {
    this._cards = new Array<PokerCard>();
  }

  // 计数扑克集中牌的数量
  public CountCards(): number {
    return this._cards.length;
  }

  // 对扑克集中的牌，根据value大小从小到大排序
  public SortAsc() {
    this._cards.sort((a, b) => a.value > b.value ? 1 : -1);
  }

  // 对扑克集中的牌，根据value大小从大到小排序
  public SortDesc() {
    this._cards.sort((a, b) => a.value < b.value ? 1 : -1);
  }

  // 将扑克集中的各个扑克牌用于某个任务
  public DoOnEachPokerCard(action: (index: number, card: PokerCard) => void) {
    const lenth = this.CountCards();
    for (let i = 0; i < lenth; i++) {
      const card = this._cards[i];
      action(i, card);
    }
  }

  // 向扑克集中添加扑克
  public AddPoker(card: PokerCard) {
    this._cards.push(card);
  }

  // 向扑克集中添加扑克
  public AddPokers(cards: Array<PokerCard>) {
    this._cards.push(...cards);
  }

  // 从扑克集中删除指定索引的扑克, 删除后扑克集元素变少
  public DeletePokerByIndex(index: number) {
    const check = this.checkIndex(index);
    if (!check) {
      return;
    }
    this._cards.splice(index, 1);
  }
  public DeletePokerByCard(card: PokerCard) {
    const index = this.GetPokerIndex(card);
    const check = this.checkIndex(index);
    if (!check) {
      return;
    }
    this._cards.splice(index, 1);
  }
  public DeletePokersByIndexs(indexs: Array<number>) {
    const check = this.checkIndexs(indexs);
    if (!check) {
      return;
    }
    indexs.sort((a, b) => a < b ? 1 : -1); // 从大到小
    for (const index of indexs) {
      this._cards.splice(index, 1);
    }
  }

  // 从扑克集中删除指定的子集
  public DeletePokers(pokers: PokerSet) {
    const indexes = this.GetPokerIndexs(pokers);
    this.DeletePokersByIndexs(indexes);
  }

  // 将指定索引的扑克牌替换
  public ReplacePoker(index: number, card: PokerCard) {
    const check = this.checkIndex(index);
    if (!check) {
      return;
    }
    this._cards[index] = card;
  }

  public get Pokers(): Array<PokerCard> {
    return this._cards;
  }

  // 根据给定索引，从扑克集中获取指定扑克
  public GetPokerByIndex(index: number): PokerCard {
    const check = this.checkIndex(index);
    if (!check) {
      return null as any;
    }
    return this._cards[index];
  }

  // 根据给定索引，从扑克集中获取子扑克集
  public GetPokersByIndexs(indexs: Array<number>): PokerSet {
    const check = this.checkIndexs(indexs);
    if (!check) {
      return null as any;
    }
    const newSet = new PokerSet();
    for (const index of indexs) {
      newSet.AddPoker(this._cards[index]);
    }
    return newSet;
  }

  // 获取指定扑克牌在扑克集中的index
  public GetPokerIndex(card: PokerCard): number {
    const lenth = this.CountCards();
    for (let i = 0; i < lenth; i++) {
      if (this._cards[i] == card) {
        return i;
      }
    }
    return -1;
  }

  // 获取指定扑克集中各扑克牌在扑克集中的indexs
  public GetPokerIndexs(pokers: PokerSet): Array<number> {
    const indexs = new Array<number>();
    for (const card of pokers._cards) {
      const index = this.GetPokerIndex(card);
      if (index > 0) {
        indexs.push(index);
      }
    }
    return indexs;
  }

  // 检查给定的索引是否存在
  public checkIndex(index: number): boolean {
    return index >= 0 && index < this.CountCards();
  }
  public checkIndexs(indexs: Array<number>): boolean {
    const lenth = this.CountCards();
    for (const index of indexs) {
      if (index < 0 || index >= lenth) { // 给定的索引超过扑克集的长度
        return false;
      }
    }
    return true;
  }

  // 检测是否有相同值的扑克牌
  public HasSameValueCard(set: PokerSet): boolean {
    for (const myCard of this._cards) {
      for (const otherCard of set._cards) {
        if (myCard == otherCard) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * 分析一组牌中, 各牌值的数量, 返回Map<number, number>
   * @returns
   */
  public AnalyzeEachCardValueNum(): Map<number, number> {
    const lenth = this.CountCards();
    if (lenth <= 0) {
      return null as any;
    }
    const cardMap = new Map<number, number>();
    for (const card of this._cards) {
      const value = card.GetValue();
      const has = cardMap.has(value);
      if (!!has) {
        cardMap.set(value, cardMap.get(value)! + 1);
      } else {
        cardMap.set(value, 1);
      }
    }
    return cardMap;
  }

  /**
   * 分析一组牌中, 各花色牌的数量, 返回Map<string, number>
   * @returns
   */
  public AnalyzeEachCardSuitNum(): Map<string, number> {
    const lenth = this.CountCards();
    if (lenth <= 0) {
      return null as any;
    }
    const cardMap = new Map<string, number>();
    for (const card of this._cards) {
      const suit = card.GetSuit();
      const has = cardMap.has(suit);
      if (!!has) {
        cardMap.set(suit, cardMap.get(suit)! + 1);
      } else {
        cardMap.set(suit, 1);
      }
    }
    return cardMap;
  }

  // 判断一组牌中, 不同数字的数量是否相同
  public IsUnsameCardNumSame(): boolean {
    const cardMap = new Map<number, number>();
    for (const card of this._cards) {
      const value = card.GetValue();
      const has = cardMap.has(value);
      if (!!has) {
        cardMap.set(value, cardMap.get(value)! + 1);
      } else {
        cardMap.set(value, 1);
      }
    }
    let isFirst = true;
    let count = 0;
    for (const cardNum of cardMap.values()) {
      if (isFirst) {
        count = cardNum;
        isFirst = false;
      } else {
        if (count != cardNum) {
          return false;
        }
      }
    }
    return false;
  }

  // 判断一组牌中, 给定索引的牌是否一样大小
  public IsAllCardSame(indexs: Array<number>): boolean {
    let isFirst = true;
    let value = -1;
    for (const index of indexs) {
      if (isFirst) {
        value = this._cards[index].GetValue();
        isFirst = false;
      } else {
        if (value != this._cards[index].GetValue()) {
          return false;
        }
      }
    }
    return false;
  }
}
